package com.appkubes.fintech.restful.application.rent.service.impl;


import com.appkubes.common.utils.data.string.UUIDUtils;
import com.appkubes.fintech.common.exption.BusinessException;
import com.appkubes.fintech.common.response.Response;
import com.appkubes.fintech.core.constant.order.RentOrderPeriodCode;
import com.appkubes.fintech.core.constant.order.RentOrderStatusCode;
import com.appkubes.fintech.core.po.*;
import com.appkubes.fintech.core.pojo.FintechRentBillHeaderMapper;
import com.appkubes.fintech.core.pojo.FintechRentOrderMapper;
import com.appkubes.fintech.restful.application.credit.dao.CreditDao;
import com.appkubes.fintech.restful.application.credit.service.CreditService;
import com.appkubes.fintech.restful.application.pay.common.contract.response.RentOrderResponse;
import com.appkubes.fintech.restful.application.rent.dao.RentOrderDao;
import com.appkubes.fintech.restful.application.rent.enums.RentBuyEnums;
import com.appkubes.fintech.restful.application.rent.enums.RentOrderEnums;
import com.appkubes.fintech.restful.application.rent.reponse.RentOrderDTO;
import com.appkubes.fintech.restful.application.rent.request.OrderKeyVO;
import com.appkubes.fintech.restful.application.rent.request.order.AddRentOrderVO;
import com.appkubes.fintech.restful.application.rent.service.IRentBillService;
import com.appkubes.fintech.restful.application.rent.service.IRentOrderService;
import com.appkubes.fintech.restful.application.user.dao.UserBaseInfoDao;
import com.appkubes.fintech.restful.application.user.service.UserBaseInfoService;
import com.appkubes.fintech.restful.util.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: xqc
 * @date: 2020/1/6 11:27
 * @params:
 * @return:
 */
@Slf4j
@Service
@Transactional
public class RentOrderServiceImpl implements IRentOrderService {
    //订单id生成器
    private final SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);

    @Autowired
    private UserBaseInfoService fintechUserBaseInfoService;

    @Resource
    private FintechRentOrderMapper fintechRentOrderMapper;

    @Autowired
    private IRentBillService billService;


    @Resource
    RentOrderDao rentOrderDao;

    @Resource
    CreditService creditService;

    @Resource
    CreditDao creditDao;
    @Resource
    private FintechRentBillHeaderMapper billHeaderMapper;
    @Resource
    private UserBaseInfoDao userBaseInfoDao;

    @Resource
    SqlSessionTemplate sqlSessionTemplate;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = BusinessException.class)
    public RentOrderDTO addRentOrder(AddRentOrderVO rentOrderVO) {
        log.info("add rent order: orderKey: {}", rentOrderVO.getOrderKey());
        RentOrderDTO rentOrderDTO = new RentOrderDTO();
        FintechRentOrderExample example = new FintechRentOrderExample();
        example.createCriteria().andOrderKeyEqualTo(rentOrderVO.getOrderKey());
        List<FintechRentOrder> rentOrderList = rentOrderDao.selectByExample(example);
        if (rentOrderList.size() > 0) {
            rentOrderDTO.setRentOrderKey(rentOrderList.get(0).getRentOrderKey());
            rentOrderDTO.setOrderKey(rentOrderList.get(0).getOrderKey());
            return rentOrderDTO;
        }
        FintechRentOrder rentOrder = queryByUserKey(rentOrderVO.getUserKey());
        if (rentOrder != null) {
            if (Objects.equals(rentOrder.getStatus(), RentOrderStatusCode.PENDING.name())
                    && !Objects.equals(1, rentOrder.getPayStatus())) {
                throw new BusinessException("订单重复，您有未完成支付账单");
            }
//            else if(Objects.equals(rentOrder.getStatus(),RentOrderStatusCode.SHIP.name())){
//                throw new BusinessException("订单重复，您有未还完账单");
//            }
//            else{
//                throw new BusinessException("订单重复，您有未买断账单");
//            }
        }

        FintechCredit credit = creditService.getCredit(rentOrderVO.getUserKey());
        Long creditAmt = credit.getCreditAmount() - credit.getFreezeAmount();
        Integer totalAmt = rentOrderVO.getRentInfoVO().getRentAmount();
        if (creditAmt.intValue() < totalAmt) {
            throw new BusinessException("授信额度不够");
        }
        rentOrder = new FintechRentOrder();
        BeanUtils.copyProperties(rentOrderVO, rentOrder);
        BeanUtils.copyProperties(rentOrderVO.getRentInfoVO(), rentOrder);
        BeanUtils.copyProperties(rentOrderVO.getReferInfoVO(), rentOrder);
        BeanUtils.copyProperties(rentOrderVO.getGoodsInfoVO(), rentOrder);
        rentOrder.setRentOrderKey(UUIDUtils.getUUID());
        rentOrder.setCreateTime(new Date());
        rentOrder.setStatus(RentOrderStatusCode.PENDING.name()); //未起租
        rentOrder.setIsSure(0);
        //根据单车的业务需求，信用额度不计算买断价
//        rentOrder.setCreditAmount(rentOrderVO.getRentInfoVO().getCreditAmount() + rentOrderVO.getRentInfoVO().getBuyOutAmount());
        //计算分期数
        //扣除信用额度
        rentOrder.setRentStartDate(DateUtils.addDays(new Date(), 1)); // T+1
        rentOrder.setUpdateTime(new Date());
        rentOrder.setUserKey(rentOrderVO.getUserKey());
        rentOrder.setInterestRate(rentOrderVO.getRentInfoVO().getInterestRate().divide(new BigDecimal(100)));
        rentOrder.setBuyOutRepayAmount(0);
        //NOTE 建议以下3个值由PeriodCode计算
//        rentOrder.setPeriodType(rentOrderVO.getPeriodType());
//        rentOrder.setPeriodDays(rentOrderVO.getPeriodLong());
//        rentOrder.setPeriods(rentOrderVO.getPeriods());
        //以下的PeriodType, PeriodDays与Periods跟上述传数是一样的，区别在于,商城不传参，由租赁系统自行配置维护
        RentOrderPeriodCode orderPeriodCode = RentOrderPeriodCode.valueOf(rentOrderVO.getRentInfoVO().getPeriodsCode());
        rentOrder.setPeriodType(orderPeriodCode.getPeriodType());
        rentOrder.setPeriodDays(orderPeriodCode.getPeriodDays());
        rentOrder.setPeriods(orderPeriodCode.getPeriods());
        rentOrder.setPayStatus(0); //未支付

        rentOrder.setBuyStatus(0); //默认未买断
        rentOrderDao.insertSelective(rentOrder);
        Response response1 = creditService.frozenCredit(rentOrder.getUserKey(), rentOrder.getCreditAmount());//冻结额度
        if (response1.getCode() != 200) {
            throw new BusinessException(response1.getMessage());
        }
        rentOrderDTO.setRentOrderKey(rentOrder.getRentOrderKey());
        rentOrderDTO.setOrderKey(rentOrder.getOrderKey());
        return rentOrderDTO;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Throwable.class)
    public RentOrderDTO ship(OrderKeyVO orderKeyVO) {
        log.info("rent order ship:" + orderKeyVO.getOrderKey() + ",userKey:" + orderKeyVO.getUserKey());
        RentOrderDTO rentOrderDTO = new RentOrderDTO();
        FintechRentOrder rentOrder = rentOrderDao.selectByPrimaryKey(orderKeyVO.getOrderKey());
        if (rentOrder == null) {
            throw new BusinessException("租售单不存在");
        }
        if (!Objects.equals(rentOrder.getStatus(), RentOrderStatusCode.PENDING.name())) {
            throw new BusinessException("租售单已启用");
        }
        if (rentOrder.getIsSure() != null && rentOrder.getIsSure() != 1) {
            throw new BusinessException("租售单未确认");
        }
        rentOrder.setUpdateTime(new Date());
        rentOrder.setStatus(RentOrderStatusCode.SHIP.name());
        rentOrderDao.updateByPrimaryKeySelective(rentOrder);


        Response<FintechRentBillHeader> response = billService.createBill(rentOrder, Integer.parseInt(orderKeyVO.getIsPayFirst()));//保存支付订单
        if (response.getCode() != 200) {
            throw new BusinessException("还租账单生成异常");
        }

        log.info("还租账单已生成");
        FintechUserBaseInfo baseInfo = userBaseInfoDao.selectByPrimaryKey(rentOrder.getUserKey());
        baseInfo.setIsNew(0);//表示老用户
        userBaseInfoDao.updateByPrimaryKey(baseInfo);
        Response response1 = creditService.unOutfrozenCredit(rentOrder.getUserKey(), rentOrder.getCreditAmount());//解冻扣除
        if (response1.getCode() != 200) {
            throw new BusinessException(response1.getMessage());
        }
        rentOrderDTO.setOrderKey(rentOrder.getOrderKey());
        rentOrderDTO.setRentOrderKey(rentOrder.getRentOrderKey());
        rentOrderDTO.setBillKey(response.getData().getBillKey());
        return rentOrderDTO;
    }

    @Override
    public RentOrderDTO cancel(OrderKeyVO orderKeyVO) {
        RentOrderDTO rentOrderDTO = new RentOrderDTO();
        FintechRentOrder rentOrder = rentOrderDao.selectByPrimaryKey(orderKeyVO.getOrderKey());
        if (rentOrder == null) {
            return rentOrderDTO;
        }
        rentOrder.setStatus(RentOrderStatusCode.CANCEL.name());
        rentOrderDao.updateByPrimaryKeySelective(rentOrder);
        Response response1 = creditService.unfrozenCredit(rentOrder.getUserKey(), rentOrder.getCreditAmount()); // 额度解冻恢复
        if (response1.getCode() != 200) {
            throw new BusinessException(response1.getMessage());
        }
        rentOrderDTO.setOrderKey(orderKeyVO.getOrderKey());
        rentOrderDTO.setRentOrderKey(rentOrder.getRentOrderKey());

        return rentOrderDTO;
    }

    @Override
    public List<FintechRentBillHeader> getByUserKey(String userKey) {
        FintechRentOrderExample example = new FintechRentOrderExample();
        FintechRentOrderExample.Criteria criteria = example.createCriteria();
        criteria.andUserKeyEqualTo(userKey);
        criteria.andStatusEqualTo("OVER");
        criteria.andBuyStatusEqualTo(RentBuyEnums.未买断.getValue());
        example.setOrderByClause(" create_time desc");
        List<FintechRentOrder> orderList = rentOrderDao.selectByExample(example);
        if (orderList.size() <= 0) {
            return null;
        }
        FintechRentBillHeaderExample headerExample = new FintechRentBillHeaderExample();
        List<String> vas = orderList.stream().map(e -> {
            return e.getRentOrderKey();
        }).collect(Collectors.toList());
        headerExample.createCriteria().andOrderKeyIn(vas);
        List<FintechRentBillHeader> billHeaderList = billHeaderMapper.selectByExample(headerExample);
        if (billHeaderList.size() <= 0) {
            return null;
        }
        return billHeaderList;
    }

    @Override
    public RentOrderResponse queryOrderKey(String orderKey) {
        RentOrderResponse rentOrderResponse = new RentOrderResponse();
        rentOrderResponse.setOrderId(orderKey);
        rentOrderResponse.setStatus("0");

        FintechRentOrderExample example = new FintechRentOrderExample();
        example.createCriteria().andOrderKeyEqualTo(orderKey);
        List<FintechRentOrder> list = rentOrderDao.selectByExample(example);

        if (list.size() <= 0) {
            return rentOrderResponse;
        }
        FintechRentOrder rentOrder = list.get(0);
        if (rentOrder.getIsSure() == null || rentOrder.getIsSure() == 0) {
            rentOrderResponse.setIsSure(0);
        } else {
            rentOrderResponse.setIsSure(1);
        }

        rentOrderResponse.setStatus(rentOrder.getStatus());
        rentOrderResponse.setBuyStatus(String.valueOf(rentOrder.getBuyStatus()));
        rentOrderResponse.setRentOrderId(rentOrder.getRentOrderKey());
        return rentOrderResponse;
    }

    //此处不建议使用事务
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Response paySuc(String orderKey) {
        log.info("paySuc :" + orderKey);
        FintechRentOrderExample example = new FintechRentOrderExample();
        example.createCriteria().andOrderKeyEqualTo(orderKey);
        List<FintechRentOrder> list = rentOrderDao.selectByExample(example);
        if (list.size() <= 0) {
            return Response.fail("租聘单不存在");
        }
        FintechRentOrder rentOrder = list.get(0);
        Integer isPay = rentOrder.getPayStatus();
        log.info("paySuc isPay:" + isPay);
        if (isPay != null && isPay == 1) {
            return Response.success("已支付成功");
        }
        rentOrder.setPayStatus(1);
        rentOrder.setUpdateTime(new Date());
        log.info("paySuc rent_order_key:{}, orderKey: {}", rentOrder.getRentOrderKey(),
                rentOrder.getOrderKey());
        Integer effectRow = rentOrderDao.updateByPrimaryKey(rentOrder);

        log.info("paySuc effectRow:" + effectRow + ", isPay:" + rentOrder.getPayStatus());
        if (effectRow > 0) {
            return Response.success();
        }
        return Response.fail("更新数据失败");
    }

    @Override
    public FintechRentOrder queryByUserKey(String userKey) {
        FintechRentOrderExample example = new FintechRentOrderExample();
        FintechRentOrderExample.Criteria criteria = example.createCriteria();
        criteria.andUserKeyEqualTo(userKey);
        List list = new ArrayList();
        list.add(RentOrderEnums.PENDING.name());
        list.add(RentOrderEnums.SHIP.name());
        criteria.andStatusIn(list);
        example.setOrderByClause("  create_time desc");
        List<FintechRentOrder> orderlist = rentOrderDao.selectByExample(example);
        if (orderlist.size() > 0) {
            return orderlist.get(0);
        }
        FintechRentOrderExample example2 = new FintechRentOrderExample();
        FintechRentOrderExample.Criteria criteria2 = example2.createCriteria();
        criteria2.andUserKeyEqualTo(userKey);
        List list2 = new ArrayList();
        list2.add(RentBuyEnums.买断中.getValue());
        list2.add(RentBuyEnums.未买断.getValue());
        criteria2.andBuyStatusIn(list2);
        orderlist = rentOrderDao.selectByExample(example2);
        if (orderlist.size() > 0) {
            return orderlist.get(0);
        } else {
            return null;
        }
    }
}
